package gov.dhs.cis.soa.readers.reqpro;

import gov.dhs.cis.soa.SOAData;
import gov.dhs.cis.soa.data.UseCase;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;

import com.rational.reqpro.rpx.Application;
import com.rational.reqpro.rpx.AttrValue;
import com.rational.reqpro.rpx._Application;
import com.rational.reqpro.rpx._AttrValues;
import com.rational.reqpro.rpx._Errors;
import com.rational.reqpro.rpx._Project;
import com.rational.reqpro.rpx._Relationship;
import com.rational.reqpro.rpx._Relationships;
import com.rational.reqpro.rpx._Requirement;
import com.rational.reqpro.rpx._Requirements;
import com.rational.reqpro.rpx.enumOpenProjectOptions;
import com.rational.reqpro.rpx.enumProjectFlags;
import com.rational.reqpro.rpx.enumRelatedProjectOptions;
import com.rational.reqpro.rpx.enumRequirementFlags;
import com.rational.reqpro.rpx.enumRequirementLookups;
import com.rational.reqpro.rpx.enumRequirementsWeights;
import com.rational.reqpro.rpx.enumTagFormat;
import com.rational.rjcb.ComObjectProxy;

public class UseCasesReport {
	static final Logger loger = Logger.getLogger(UseCasesReport.class);
	public static final String REQPRO_PROJECT = "C:\\Projects\\ReqPro\\Projects\\USCIS Transformation 02072011\\Requirements.rqs";
	public static final String REQPRO_USER = "admin";	//"readonly";
	public static final String REQPRO_PASS = "";	//"uscis";
	public static final String COL_SEP = "|";
	public static final String OUT_FILE = "C:\\UCReport.xls";
	
	public static final String LINE_SEP = "\n";
	
	FileOutputStream fstream = null;
    BufferedWriter out = null;
    HSSFWorkbook book = null;
    HSSFSheet sheet = null;
	String[] header = new String[] { "P.UC #", "UC #", "U.Name", "WIPT", "Rel", "IST", 
			"StartItr", "EndItr", "Type", "L3 Bus", "UC Desc", "R.Type", "R.UC#", "R.U.Name", 
			"R.U.Desc", "SrvID", "SrvName" };  

	ArrayList<String> toPrint = new ArrayList<String>();
    int nCurrentRow = 0;
    
	_Application RPX = null;
	_Project project = null;
	public SOAData extractUseCases(SOAData soaData) {
		try {
			RPX = new Application();
			project = RPX.OpenProject(REQPRO_PROJECT,
					enumOpenProjectOptions.eOpenProjOpt_RQSFile, REQPRO_USER,
					REQPRO_PASS, enumProjectFlags.eProjFlag_ReadOnly,
					enumRelatedProjectOptions.eRelatedProjOption_ConnectNone);
//			_Requirements requs = project.GetRequirements("UC", enumRequirementLookups.eReqLookup_Tag, 
//					enumRequirementsWeights.eReqWeight_Medium, enumRequirementFlags.eReqFlag_Empty,
//					200, 40);
			_Requirements requs = project.GetRequirements("SERV", enumRequirementLookups.eReqLookup_Tag, 
					enumRequirementsWeights.eReqWeight_Rels, enumRequirementFlags.eReqFlag_Empty,
					200, 40);
			int reqCount = requs.getCount();
			System.out.println("Req Count : " + reqCount);
			int ucCount = 0;
			ArrayList<UseCase> useCaseList = new ArrayList<UseCase>();
			soaData.useCaseList = useCaseList;
			
			if(reqCount > 0) {
				fstream = new FileOutputStream(OUT_FILE);
			    //out = new BufferedWriter(fstream);

			    book = new HSSFWorkbook();
			    sheet = book.createSheet("Report");
			    printHeader();
			    
			    requs.MoveFirst();
				_Requirement req = null;
				
				int ucStartNum = 0;
				int ucReqNum = 0;
				for(int i = 0; /*ucCount < 2 &&*/ i < reqCount; i++) {
					req = requs.GetCurrentRequirement();
					ucReqNum = Integer.parseInt(req.getTag(enumTagFormat.eTagFormat_TagRootNumber));
					//System.out.println(req.getKey());
					if(req.getLevel() == 0) {
						ucCount++;
						if(ucReqNum >= ucStartNum) 
							useCaseList.add(readRequirement(null, req));
					}
					requs.MoveNext();
				}
			}
			System.out.println("Total UC count : " + ucCount);
			
			project.CloseProject();
			ComObjectProxy obj = (ComObjectProxy) RPX;
			obj.release();
			RPX= null;			
		} catch (Exception e) {
			try {
				_Errors err = RPX.getErrors();
				System.out.println(err.getAllMessages());
				e.printStackTrace();
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}				
		} finally {
			try {
				if(out != null) {
					out.close();
				}
				if(book != null) {
					CellRangeAddress range = new CellRangeAddress(0, this.nCurrentRow-1, 0, header.length-4);
					sheet.setAutoFilter(range);
					book.write(fstream);
					fstream.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return soaData;
	}

	private UseCase getRequirementAttrs(UseCase u, _Requirement req) throws Exception {
		_AttrValues types = req.getAttrValues();
		int count = types.getCount();
		if(count <= 0)
			return u;
		//System.out.println("RequirementAttrs# :" + count);
		Enumeration e = types.NewEnum();
		boolean isObsolete = false;
		while(e.hasMoreElements()) {
			AttrValue type = new AttrValue(e.nextElement());
			//System.out.println(type.getLabel() + " : " + type.getText());
			if("Management Function".equalsIgnoreCase(type.getLabel())) {
				u.wipt = type.getText();
			} else if("Use Case Number".equalsIgnoreCase(type.getLabel())) {//"Increment 1 Identifier"
				u.unumber = "UC" + type.getText();
			} else if("Planned First Release".equalsIgnoreCase(type.getLabel())) {
				u.release = type.getText();
			} else if("Service Definition".equalsIgnoreCase(type.getLabel())) {
				u.stereotype = ("Yes".equalsIgnoreCase(type.getText()) ? "SD" : "UC");
			} else if("L3 Process".equalsIgnoreCase(type.getLabel())) {
				u.busProcessName = type.getText();
			} else if("Working Status".equalsIgnoreCase(type.getLabel())) {
				u.status = 	type.getText();
				u.modSiceIRR = type.getText();
			} else if("Obsolete".equalsIgnoreCase(type.getLabel())) {
				if("True".equalsIgnoreCase(type.getText()))
					isObsolete = true;
			} else if("IST".equalsIgnoreCase(type.getLabel())) { 	//added as part 02/07/2011 baseline reporting - RSingh 02/08/2011
				u.IST = type.getText();
			} else if("Start Iteration".equalsIgnoreCase(type.getLabel())) { 	//added as part 02/07/2011 baseline reporting - RSingh 02/08/2011
				u.startItr = type.getText();
			} else if("Completion Iteration".equalsIgnoreCase(type.getLabel())) {	//added as part 02/07/2011 baseline reporting - RSingh 02/08/2011
				u.endItr = type.getText();
			}
		}
		if(isObsolete)	//overwrite release as O - obsolete. RSingh 12/13/2010
			u.release = "O";
		return u;
	}

	public ArrayList<_Requirement> getTraceFromList(_Requirement req) throws Exception {
		ArrayList<_Requirement> retList = null;
		_Relationships rels = req.getTracesFrom();
		Enumeration<String> relsEnum = rels.NewEnum();
		String relNameStr = "";
		if(rels != null && rels.getCount() > 0) {
			rels.MoveFirst();
			retList = new ArrayList<_Requirement>();
			while (!rels.IsEOF()) {
				relNameStr = relsEnum.nextElement();
				_Relationship childRel = rels.GetCurrentRelationship();
				_Requirement srcReq = childRel.getSourceRequirement(0);
				String prefix = srcReq.getReqType().getReqPrefix();
				if("BR".equalsIgnoreCase(prefix)) {
					System.out.println(childRel.getRelationshipTypeName() + " - " + 
							childRel.getSourceKey() + " - " + srcReq.getKey() + " - " + relNameStr);
				} else {
					retList.add(srcReq);
				}
				rels.MoveNext();
			}
		}

		return retList;
	}

	public ArrayList<String> getTraceFromList2(_Requirement req) throws Exception {
		ArrayList<String> retList = null;
		_Relationships rels = req.getTracesFrom();
		Enumeration<String> relsEnum = rels.NewEnum();
		String relNameStr = "";
		if(rels != null && rels.getCount() > 0) {
			//rels.MoveFirst();
			retList = new ArrayList<String>();
			while(relsEnum.hasMoreElements()) {
				relNameStr = relsEnum.nextElement();
				//System.out.println(" ---" + relNameStr);
				//_Relationship childRel = rels.GetCurrentRelationship();
				//System.out.println(childRel.getRelationshipTypeName() + " = " + childRel.getDestinationKey() + " -> " + childRel.getSourceKey());
				//split..
				int idx = relNameStr.lastIndexOf("}");
				if(idx > 0) {
					String number = relNameStr.substring(idx+1);
					_Requirement relReq = add2LookupList(number /*, rels.GetCurrentRelationship()*/);
					retList.add(number);
					if(relReq != null) {
						String prefix = relReq.getReqType().getReqPrefix();
						if("TASK".equalsIgnoreCase(prefix))
							getTraceToServDef(number, relReq);
					}
				}
				//add2LookupList(relNameStr /*, rels.GetCurrentRelationship()*/);
				//rels.MoveNext();
			}
		}

		return retList;
	}

	public void getTraceToServDef(String parentTaskKey, _Requirement req) throws Exception {
		ArrayList<String> retList = null;
		_Relationships rels = req.getTracesTo();
		Enumeration<String> relsEnum = rels.NewEnum();
		String relNameStr = "";
		String ucTag = "";
		String ucName = "";
		String ucFullName = "";
		if(rels != null && rels.getCount() > 0) {
			retList = lookList(parentTaskKey);
			while(relsEnum.hasMoreElements()) {
				relNameStr = relsEnum.nextElement();
				//System.out.println(" ---" + relNameStr);
				//split..
				int idx = relNameStr.indexOf("}");
				if(idx > 0) {
					String number = relNameStr.substring(idx+1, relNameStr.indexOf("{", idx));
					ucFullName = (String) servKeysLookup.get(number);
					if(ucFullName == null) {
						_Requirement relReq = findReqByKey(number);
						if("SERV".equalsIgnoreCase(relReq.getReqType().getReqPrefix())) {
							System.out.println(relReq.getReqType().getReqPrefix() + " - " + relReq.getName());
							ucTag = relReq.getTag(enumTagFormat.eTagFormat_FullTag);
							ucName = relReq.getName();
							ucFullName = ucTag + "+" + ucName;
							servKeysLookup.put(number, ucFullName);
						}
					} else {
						String[] toks = ucFullName.split("[+]");
						ucTag = toks[0];
						ucName = toks[1];
						//System.out.println(ucTag + " - " + ucName);
					}
					if(ucFullName != null) {
						retList.add(ucTag); 
						retList.add(ucName);
					}
				}
			}
		}

		return;
	}

	HashMap<String, ArrayList<String>> keysLookup = new HashMap<String, ArrayList<String>>();
	HashMap<String, String> servKeysLookup = new HashMap<String, String>();
	
	private ArrayList<String> lookList(String key) {
		ArrayList<String> ret = keysLookup.get(key);
		return ret;
	}
	
	private _Requirement findReqByKey(String key) throws Exception {
		_Requirement relReq = project.GetRequirement(key, enumRequirementLookups.eReqLookup_Key, 
				enumRequirementsWeights.eReqWeight_Medium, enumRequirementFlags.eReqFlag_Empty);
		return relReq;
	}
	private _Requirement add2LookupList(String key/*, _Relationship childRel*/) throws Exception {
		ArrayList<String> retList = lookList(key);
		if(retList != null)
			return null;
		_Requirement relReq = findReqByKey(key);
		//_Requirement relReq = childRel.getSourceRequirement(0);
		//String prefix = relReq.getReqType().getReqPrefix();
		//if(!"BR".equalsIgnoreCase(prefix)) {
			retList = new ArrayList<String>();
			retList.add(relReq.getReqType().getReqPrefix()); 
			retList.add(relReq.getTag(enumTagFormat.eTagFormat_FullTag)); 
			retList.add(relReq.getName());
			retList.add(relReq.getText());
			keysLookup.put(key, retList);
			return relReq;
		//}
		//return null;
	}
	
	public UseCase readRequirement(UseCase parReqUC, _Requirement req) throws Exception {
		UseCase u = new UseCase();
		u.uname = req.getName();
		u.descText = req.getText();
		u.reqprodbid = req.getTag(enumTagFormat.eTagFormat_FullTag);

		if(req.getLevel() == 0)
			getRequirementAttrs(u, req);
		//As part 02/07/2011 baseline extract, UC number is an attribute now - RSingh 02/08/2011
		u.unumber = req.getTag(enumTagFormat.eTagFormat_FullTag);
		
		toPrint.clear();
		
		toPrint.add(parReqUC == null ? "None" : parReqUC.unumber);
		toPrint.add(u.unumber);
		toPrint.add(u.uname);
		toPrint.add((parReqUC == null ? u.wipt : parReqUC.wipt));
		toPrint.add((parReqUC == null ? u.release : parReqUC.release));
		//added as part 02/07/2011 baseline reporting - RSingh 02/08/2011
		//toPrint.add(u.reqprodbid);
		toPrint.add((parReqUC == null ? u.IST : parReqUC.IST));
		toPrint.add((parReqUC == null ? u.startItr : parReqUC.startItr));
		toPrint.add((parReqUC == null ? u.endItr : parReqUC.endItr));
		//end 02/08/2011
		toPrint.add((parReqUC == null ? u.stereotype : parReqUC.stereotype));
		toPrint.add((parReqUC == null ? u.busProcessName : parReqUC.busProcessName));
		toPrint.add((parReqUC == null ? u.descText : ""));
		
		ArrayList<String> relatedReqs = getTraceFromList2(req);
		String lineOut = "";
		if(relatedReqs != null && relatedReqs.size() > 0) {
			ArrayList<String> tempList = null;
			int addedCount = 0;
			for (String relReq : relatedReqs) {
				tempList = lookList(relReq);
				if(tempList == null) {
					System.out.println("CRASH  -- " + relReq);
					continue;
				}
				addedCount = tempList.size();
				toPrint.addAll(tempList);
				/*
				toPrint.add(relReq.getReqType().getReqPrefix()); 
				toPrint.add(relReq.getTag(enumTagFormat.eTagFormat_FullTag)); 
				toPrint.add(relReq.getName());
				toPrint.add(relReq.getText());
				*/
				print2File(toPrint);
				for(;addedCount > 0;addedCount--)
					toPrint.remove(toPrint.size()-1);
			}
		} else if (parReqUC == null) {
			toPrint.add(""); 
			toPrint.add(""); 
			toPrint.add(""); 
			toPrint.add(""); 
			print2File(toPrint);
			toPrint.remove(toPrint.size()-1);
			toPrint.remove(toPrint.size()-1);
			toPrint.remove(toPrint.size()-1);
			toPrint.remove(toPrint.size()-1);
			
		}
		_Relationships rels = req.getChildren();
		if(rels != null && rels.getCount() > 0) {
			rels.MoveFirst();
			while (!rels.IsEOF()) {
				_Relationship childRel = rels.GetCurrentRelationship();
				_Requirement srcReq = childRel.getDestinationRequirement(0);
				readRequirement((parReqUC == null ? u : parReqUC), srcReq);
				rels.MoveNext();
			}
		}
		return u;
	}	
	
	private void print2File(ArrayList<String> toPrint) {
		if(sheet == null) {
			boolean firstOne = true;
			for(String str : toPrint) {
				if(!firstOne)
					System.out.print(COL_SEP);
				System.out.print(str);
			}
			System.out.print(LINE_SEP);
			return;
		}
		HSSFRow row = sheet.createRow(nCurrentRow++);
		String data = null;
		for(int i = 0; i < toPrint.size(); i++) {
			data = (String)toPrint.get(i);
			HSSFCell cell = row.createCell(i);
			/*
			HSSFCellStyle style = book.createCellStyle();
			if(data.length() > 130) {
				style.setWrapText(true);
				sheet.setColumnWidth(i, 20000);
			} else {
				sheet.setColumnWidth(i, 7500);
			}
			style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
			cell.setCellStyle(style);
			*/
			cell.setCellValue(data);
		}
	}

	private void printHeader() {
		HSSFRow row = sheet.createRow(nCurrentRow++);
		String data = "";
		for(int i = 0; i < header.length; i++) {
			data = (String)header[i];
			HSSFCell cell = row.createCell(i);
			HSSFCellStyle style = book.createCellStyle();
			style.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
			style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
			style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
			style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
			cell.setCellStyle(style);
			cell.setCellValue(data);
		}
	}

	public void printUseCases(SOAData soaData) {
		ArrayList<UseCase> useCaseList = (ArrayList<UseCase>) soaData.useCaseList;
		for(UseCase u : useCaseList) {
			//System.out.println(u.reqprodbid + "," + u.unumber + "," + u.uname + "," + u.status + "," + u.descText + "," + u.wipt + "," + u.release + "," + u.busProcessName );
			System.out.println(u.reqprodbid + "," + u.unumber + "," + u.uname + "," + u.status + "," + u.wipt + "," + u.release + "," + u.busProcessName );
		}
	}
	
	/**may be dev 
	 * @param args
	 */
	public static void main(String[] args) {
		UseCasesReport pr = new UseCasesReport();
		try {
			SOAData sData = new SOAData();
			pr.extractUseCases(sData);
			pr.printUseCases(sData);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
